/**
 * 根据选择器查找满足条件的第一个元素
 * @param selector 选择器
 * @return 满足选择器条件的第一个元素
 */
function $(selector) {
    return document.querySelector(selector)
}

/**
 *多属性运动动画函数
 * @param {*} element 待添加运动动画效果的DOM元素
 * @param {*} options 存放要实现动画效果的属性以及该属性的最终值的对象
 * @param {*} duration 限定运动的总时长
 * @param {*} fn 可选参数，动画执行完后需要调用的函数
 */
function animate(element, options, duration, fn) {
    clearInterval(element.timer)
    const start = {}
    const speed = {}
    for (const key in options) {
        start[key] = parseFloat(window.getComputedStyle(element, null)[key])
        speed[key] = (options[key] - start[key]) / duration
    }
    const startTime = Date.now()

    function move() {
        const elapsed = Math.min(duration, Date.now() -
            startTime)
        for (const key in options) {
            const result = elapsed * speed[key] + start[key]
            element.style[key] = result + (key === 'opacity' ? '' : 'px')
        }
        if (elapsed !== duration) {
            element.timer = setTimeout(move, 1000 / 60)
        } else {
            fn && fn()
        }
    }
    move()
}
/**
 *淡入效果函数
 * @param {*} element 执行淡入效果的元素
 * @param {*} duration 淡入效果时长
 * @param {*} fn
 */
function fadeIn(element,duration,fn){
    element.style.display = 'block'
    element.style.opacity = 0
    animate(element, {opacity: 1}, duration, fn)
}
/**
 *淡出效果函数
 * @param {*} element 执行淡出效果的元素
 * @param {*} duration 淡出效果时长
 * @param {*} fn
 */
function fadeOut(element,duration,fn){
    animate(element, {opacity: 0}, duration, () => {
        element.style.display = 'none'
        fn && fn()
      })
}

/**
 *产生一个min~max范围内的随机整数
 * @param {*} min 随机数的最小值
 * @param {*} max 随机数的最大值
 * @return {*} 返回生成的随机数
 */
function random(min, max) {
    return Math.floor(Math.random() * (max - min)) + min
}


//以下为兼容性适配
/**
 * 根据类名查找元素
 * @param {*} className 类名
 * @return 根据类名查找到的元素数组（类数组对象）
 */
function getElementsByClassName(className) {
    // 支持，则直接使用
    if (document.getElementsByClassName) {
        return document.getElementsByClassName(className)
    }
    // 不支持，实现兼容写法
    var result = []
    var tags = document.getElementsByTagName('*')
    for (var i = 0, len = tags.length; i < len; i++) {
        // 当前遍历到元素使用的所有类名
        var classNames = tags[i].className.split(' ')
        // 遍历所有类名
        for (var j = 0, l = classNames.length; j < l; j++) {
            if (classNames[j] === className) {
                result.push(tags[i])
                break
            }
        }
    }
    return result
}

/**
 * 获取或设置 css 样式
 * @param element DOM 元素节点
 * @param name CSS 属性名称
 * @param value CSS 属性值
 */
function css(element, name, value) {
    // value 参数未传递
    if (typeof value === 'undefined') {
        // 根据属性名获取属性值
        if (typeof name === 'string') {
            // 根据 css 属性名获取对应属性值
            if (window.getComputedStyle) {
                return window.getComputedStyle(element, null)[name]
            }
            return element.currentStyle[name] // IE9 之前
        } else if (typeof name === 'object') {
            // 设置 css 样式
            for (var key in name) {
                element.style[key] = name[key]
            }
            return
        }
    }
    // 设置 css 样式
    element.style[name] = value
}

/**
 * 注册事件监听
 * @param {*} element
 * @param {*} eventType
 * @param {*} callback
 */
function on(element, eventType, callback) {
    if (element.addEventListener) {
        element.addEventListener(eventType, callback, false)
    } else {
        eventType = 'on' + eventType
        element.attachEvent(eventType, callback)
    }
}

/**
 * 移除事件监听
 * @param {*} element
 * @param {*} eventType
 * @param {*} callback
 */
function off(element, eventType, callback) {
    if (element.removeEventListener) {
        element.removeEventListener(eventType, callback, false)
    } else {
        eventType = 'on' + eventType
        element.detachEvent(eventType, callback)
    }
}

/**
 *
 *
 * @param {*} url
 * @param {*} success
 * @param {*} error
 */
function getAJAX(url, success, error) {
    const xhr = new XMLHttpRequest()
    xhr.open('GET', url, true)
    xhr.send()
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                const data = xhr.responseText
                success && success(data)
            } else {
                error && error(xhr.status)
            }
        }
    }
}

/**
 *
 *
 * @param {*} url
 * @param {*} data
 * @param {*} success
 * @param {*} error
 */
function postAJAX(url, data, success, error) {
    const xhr = new XMLHttpRequest()
    xhr.open('POST', url, true)
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    xhr.send(data)
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                const data = xhr.responseText
                success && success(data)
            } else {
                error && error(xhr.status)
            }
        }
    }
}

/**
 * 使用promise的get方式AJXA传输
 * @param {*} url 请求数据的地址
 * @return {*} 返回一个promis对象
 */
function getAJAXWithPromise(url) {
    const promise = new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()
        xhr.open('GET', url, true)
        xhr.send()
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    let data = xhr.responseText
                    data=JSON.parse(data)
                    resolve(data)
                } else {
                    reject(xhr.status)
                }
            }
        }
    })
    return promise
}

/**
 * 使用promise的post方式AJXA传输
 * @param {*} url 请求数据的地址
 * @param {*} data 需要向服务器发送的数据
 * @return {*} 返回一个promise对象
 */
function postAJAXWithPromise(url,data){
    const promise=new Promise((resolve,reject)=>{
        const xhr=new XMLHttpRequest()
        xhr.open('POST',url,true)
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
        xhr.send(data)
        xhr.onreadystatechange=function(){
            if(xhr.readyState===4){
                if(xhr.status===200){
                    let data=xhr.responseText
                    data=JSON.parse(data)
                    resolve(data)
                }else{
                    reject(xhr.status)
                }
            }
        }
    })
    return promise
}

/**
 * 保存cookie
 * @param {*} name cookie的名称
 * @param {*} value cookie的值
 * @param {*} [options={}] 可选选项：{expires: 7, path, domain, secure}
 */
function setCookie(name,value,options={}){
    //处理失效时间
    if(options.expires){
        //获取当前保存cookie的时间
        const datetime=new Date()
        //使用当前获取到的时间加上传过来的时间，就得到cookie的到期时间
        datetime.setDate(datetime.getDate+options.expires)
        //将得到的时间转换成标准时间字符串赋值给原来传过来的时间，就得到一个正确的cookie失效时间
        options.expires=datetime.toUTCString
    }
    //构建cookie数组
    const cookie=[
        encodeURIComponent(name),//将传过来的cookie的name值进行编码处理，避免出现中文乱码
        '=',
        encodeURIComponent(value),//将传过来的cookie的value值，进行编码，避免出现中文乱码
        options.expires?`; expires=${options.expires}`:'',
        options.path?`; path=${options.path}`:'; path=/',
        options.domain?`; domain=${options.domain}`:'',
        options.secure?'; secure':''
    ].join('')//将数组使用join()方法连接成字符串
    document.cookie=cookie//将数据存入cookie中
}

/**
 * 删除cookie
 * @param {*} name 需要删除的cookie的名字
 * @param {*} [options={}] 可选选项：{expires: 7, path, domain, secure}，7表示cookie的时效为7天
 */
function removeCookie(name,options={}){
    //直接把cookie的失效时间设置为当前时间过去的时间点就能自动删除cookie
    options.expires=-1
    setCookie(name,'',options)
}

/**
 * 查询cookie
 * @param {*} name 需要查询的cookie的名字
 * @return {*} 返回查找到的cookie值，未查找到则返回null
 */
function getCookie(name){
    //获取总的所有cookie，以分号空格隔开
    const cookies=document.cookie.split('; ')
    //遍历每一条cookie
    for(let i=0;i<cookies.length;i++){
        //cookies中的每一项都是一个'key=value; '形式的字符串，把每一项以 = 分隔开，变成一个数组
        const part=cookies[i].split('=')
        //数组的第一项为cookie名
        const key=decodeURIComponent(part.shift())
        //数组的其余元素使用 = 号拼接后为cookie值
        const value=decodeURIComponent(part.join('='))
        //判断当前遍历到的key名是否为传入的name，是就返回cookie值
        if(key===name){
            return value
        }
    }
    //未查找到返回null
    return null
}